
-- 配置文件管理

local require = require;
local ngx     = ngx;
local pairs   = pairs;
local string  = string;
local table   = table;
local os      = os;
local string = string;
local os_date = os.date;
local tonumber = tonumber;
local type = type
local math = math

local table_insert     = table.insert
local table_concat     = table.concat

local string_find = string.find

local uu         = require("modules.commhm.utils");
local log        = require("modules.commhm.log");
local ns_time    = require("modules.commhm.time");
local ns_network =  require("modules.commhm.network");

local ns_env     = require("modules.env.env");

local ns_config  = require("modules.center_server.center_config")

local ns_const_vars = require("modules.commhm.const_vars")

local CLuaConfig    = require("modules.center_server.CLuaConfig")
local gg            = require("modules.center_server.center_gg")

local ns_auth_comm_checker = require("modules.commhm.auth_comm_checker")

local ns_html_keeper_list   = require( "modules.center_server.html.keeper_list" )
local ns_html_keeper_detail = require( "modules.center_server.html.keeper_detail" )
local ns_html_dc_list       = require( "modules.center_server.html.dc_list" )
local ns_html_ma_gate_list  = require( "modules.center_server.html.ma_gate_list" )


local table_tostring = table.tostring
local table_loadstring = table.loadstring


local FOO = {
	_VERSION = '0.12.1',

	---5个环境
	lua_info_list = {
		[0] = {},    ---正式
		[1] = {},    ---测试
		[2] = {},    ---先遣
		[10] = {},   ---海外正式
		[11] = {},   ---海外测试
		[12] =    ---海外先遣
		{
			--- version
			--- ma_config
			--- map_topic
		},
		cc = 0,  ---计数
	},

	lua_config_ver_time   = 1,   ---lua文件的版本号
};


local _SEND_TIME_OUT_ = 20000   --国内10秒 海外20秒左右



---php通知中心服，需要同步配置文件
function FOO.infoNeedRsyncLuaConfigFiles()
	uu.set_nginx_share( "lua_config_ver_time", uu.now() );
	log.day_list( "center_server", ngx.worker.id(), "lua_config_ver_time", "infoNeedRsync", uu.now() )
	gg.return_table( {ret=0} )
end


---同步配置文件
function FOO.rsyncLuaConfigFiles()

	local function rsync_by_path_( path_ )

		local ip_ = '120.24.64.132'
		--if  ns_env.debug == 10 or ns_env.debug == 11 or ns_env.debug == 12 then
			--ip_ = '8.210.74.80'
		--end

		--- 从132 php 配置环境同步最新配置文件
		uu.create_dir_if( ns_config.center_lua_config_dir_root .. path_ )
		local cmd_ = 'rsync --progress --port=8873 -ptvrcz --include="*.lua" --exclude="*"'
				.. ' samba@'.. ip_ .. '::132_haima_lua_config_r/' .. path_ .. ' '
				.. ns_config.center_lua_config_dir_root .. path_
				.. ' --password-file /home/rsync_132.secrets_lua_config_r'
		local ret_exe = uu.os_execute( cmd_ );
		log.debug( "copy=" .. (ret_exe or "nil") );
		log.day_list( "center_server", ngx.worker.id(), "rsyncLuaConfigFiles", path_, ret_exe )
	end

	rsync_by_path_( 'foreign/ma/' )  ----同步海外
	rsync_by_path_( 'ma/' )          ----同步国内
end



--- 计算所有文件的md5值 by env
--- 1 本服务器启动的时候，计算一次
--- 2 当配置php服务器推送文件变化消息的时候，计算一次
function FOO.calAllLuaMd5()

	local 	new_lua_info_list_ = {
		[0] = {},    ---正式
		[1] = {},    ---测试
		[2] = {},    ---先遣
		[10] = {},   ---海外正式
		[11] = {},   ---海外测试
		[12] =       ---海外先遣
		{
			--- version = { md5, file_size, file_content }
			--- ma_config
			--- map_topic
		},
		cc = 0,  ---计数
	}

	local all_change_cc_ = 0

	for env_, info_list_ in pairs( new_lua_info_list_ ) do
		if  type(env_) == 'number' then
			local file_cc_, change_cc_ = FOO.calAllLuaMd5ByEnv( env_ )
			log.day_list( "center_server", ngx.worker.id(), "calAllLuaMd5_evn",
					env_, change_cc_, file_cc_ )

			new_lua_info_list_.cc = new_lua_info_list_.cc + file_cc_
			all_change_cc_ = all_change_cc_ + change_cc_
		end
	end

	log.day_list( "center_server", ngx.worker.id(), "calAllLuaMd5", all_change_cc_, new_lua_info_list_.cc )

	if  all_change_cc_ > 0 then
		FOO.lua_info_list = new_lua_info_list_    ---仅提供给 getLuaConfigFileInfo 判断环境使用
	else
		log.debug( "no lua config changed" )
	end

end


---计算单个环境的配置文件
function FOO.calAllLuaMd5ByEnv( env_ )

	local file_count_ = 0
	local change_cc_  = 0

	---需要同步的文件列表
	for i=1, #ns_const_vars.all_lua_configs.file_names do
		if  FOO.calOneLuaConfigFile( ns_const_vars.all_lua_configs.file_names[i], env_ ) == 1 then
			change_cc_ = change_cc_ + 1
		end
		file_count_ = file_count_ + 1
	end


	for i=1, #ns_const_vars.all_lua_configs.copy_file_names do
		if  FOO.calOneLuaConfigFile( ns_const_vars.all_lua_configs.copy_file_names[i], env_ ) == 1 then
			change_cc_ = change_cc_ + 1
		end
		file_count_ = file_count_ + 1
	end

	log.debug( "=========== env=" .. env_ .. ", change_cc=" .. change_cc_ )
	--uu.var_dump( info_list_ )

	return file_count_, change_cc_
end


---计算一个文件是否有变化
function FOO.calOneLuaConfigFile( lua_short_name_, env_ )
	local lua_config_ = CLuaConfig:new( ns_config.center_lua_config_dir_root, lua_short_name_, env_ )
	local size_ = uu.get_file_size( lua_config_:getFullPath() )
	if  size_ <= 0 then
		--log.error( "file_size_error:" .. lua_config_.path_file_name )
		log.day_list( "center_server", ngx.worker.id(), "calOneLuaConfigFile", "size_error", lua_short_name_, env_ )
		return 0
	end

	local md5_ = uu.get_file_md5( lua_config_:getFullPath() )

	---把md5写入share中
	local key_ = 'md5_' .. env_ .. '_' .. lua_short_name_

	local md5_old_ = uu.get_server_cache_string( 1, key_ )
	--log.day_list( "center_server", ngx.worker.id(), "md5_compare", key_, md5_old_, md5_, lua_config_:getFullPath() )

	if  md5_old_ and md5_old_ == md5_ then
		--- same md5
		uu.set_ttl_server_cache( 1, key_, 86400*30 )
	else
		uu.set_server_cache_string( 1, key_, md5_, 86400*30 )
		log.day_list( "center_server", ngx.worker.id(), "calOneLuaConfigFile", md5_, key_ )
		return 1   ---有变化
	end

	return 0    ---无变化
end


-----------------------------------------------------------

---获取一批文件的md5值和下载地址
function FOO.getLuaConfigFileInfo()
	if  ngx.ctx.m_params.env and ngx.ctx.m_params.fn then

		local env_ = tonumber(ngx.ctx.m_params.env)
		if  not ( env_ and FOO.lua_info_list[env_] ) then
			gg.return_table( { ret=99, msg="error_env" } )
			return
		end


		----记录远程信息
		local info_ = {
			e = env_,
			n = ngx.ctx.m_params.server_name or "n",
			t = uu.now(),
		}
		FOO.record_remote_ip( info_ )

		local key_ = 'md5_' .. env_ .. '_' .. ngx.ctx.m_params.fn
		--log.debug( "key_=" .. key_ )
		local msg_

		local md5_ = uu.get_server_cache_string( 1, key_ )
		if  md5_ and #md5_ > 10 then
			if  ngx.ctx.m_params.fn_md5 and ngx.ctx.m_params.fn_md5 == md5_ then
				---未变化
				gg.return_table( { ret=0 } )    ---unchanged
				-- msg_ = "ok0"
			else
				---下发最新的md5和文件内容
				local lua_config_ = CLuaConfig:new( ns_config.center_lua_config_dir_root,
						ngx.ctx.m_params.fn, env_ )
				local content_base64_ = lua_config_:getContentBase64()
				if  content_base64_ then
					gg.return_table( { ret=1, md5=md5_, content_base64=content_base64_ } )
					msg_ = "ok1"
				else
					gg.return_table( { ret=2, msg="lua_config_content_not_found" } )
					msg_ = "not_found2"
				end
			end
		else
			log.error( "lua_config_not_found:" .. key_,  'center_server_258' )
			gg.return_table( { ret=3, msg="lua_config_not_found" } )
			msg_ = "error_not_found3"
		end

		if  msg_ then
			log.day_list( "center_server", key_, ngx.ctx.m_params.worker_id, msg_ )
		end

	else
		gg.return_table( { ret=99, msg="error_params" } )
		log.day_list( "center_server", "error_params", ngx.ctx.m_params.worker_id, ngx.ctx.m_params.fn_md5 )
	end

end



---检查文件是否有变化了 lua_config_ver_time
---uu.set_nginx_share( "lua_config_ver_time", uu.now() );
function FOO.worker_checkLuaConfigChanged()

	if  uu.check_server_time_interval( "w_clcc", 60 ) then
		--log.day_list( "center_server", ngx.worker.id(), "w_clcc_in_ignore" )
		return
	end

	---- 只有单个worker可以rsync和改写file信息
	---- 忙的时候 其他worker只读不写
	local ver_ = uu.get_nginx_share( "lua_config_ver_time" );
	if  ver_ == FOO.lua_config_ver_time then
		---版本未变化
		--log.day_list( "center_server", ngx.worker.id(), "lua_config_ver_time", "same", ver_ )
	else
		log.day_list( "center_server", ngx.worker.id(), "lua_config_ver_time", "changed",
				ver_, FOO.lua_config_ver_time )
		---需要重新加载
		FOO.lua_config_ver_time = ver_
		FOO.rsyncLuaConfigFiles()
		FOO.calAllLuaMd5()
	end

end



------------------------------------------------------------
----刷新调用者IP信息   t = {["t"]=1609991175,["e"]=1,["n"]="manor"}
function FOO.record_remote_ip( t_ )
	local keeper_list_
	if  t_.n == 'keeper_server' then
		keeper_list_ = ngx.shared.keeper_server_list    ---keeper_server的上报
	else
		keeper_list_ = ngx.shared.keeper_list           ---其他模块的上报 比如ma map
	end

	local key_ = ngx.var.remote_addr or "no_ip"

	local last_ = 0
	local str_ = keeper_list_:get(key_)
	if  str_ then
		local info_ = table.loadstring( str_ )
		if  info_ and info_.t then
			last_ = info_.t
		end
	end

	local time_ = t_.t - last_
	if  time_ > 120 then
		local value_ = table.tostring( t_ )
		keeper_list_:set( key_, value_, 7*86400 )   --保存7天，用来检查掉线的情况
		log.day_list( "center_server", ngx.worker.id(), "record_remote_ip_120", key_, value_, time_ )
	end

end



----遍历所有ip
function FOO.getKeeperList()

	if  ngx.ctx.m_params.gm_name then
		---ok
	else
		ngx.say( "正在开发中" )
		return
	end

	---来自keeper_server的上报
	local keeper_server_list_ = ngx.shared.keeper_server_list
	local keys_keeper_        = keeper_server_list_:get_keys(4096)
	uu.var_dump(keys_keeper_)

	---来自其他服务的上报 比如ma map
	local keeper_list_ = ngx.shared.keeper_list
	local keys_other_  = keeper_list_:get_keys(4096)
	uu.var_dump(keys_other_)

	local stdmap_ip_ = {}
	local all_keeper_list_ = {}

	local env_filter_   ---env过滤
	if  ngx.ctx.m_params.env_filter then
		env_filter_ = tonumber(ngx.ctx.m_params.env_filter )
	end


	---获得上报的详情
	for index_, ip_ in pairs(keys_keeper_) do
		local str_ = keeper_server_list_:get(ip_)
		if  log.fast() then
			log.debug_list( index_, ip_ , str_ )
		end

		local time_ = 0
		local k_ = table.loadstring( str_ )
		if  type(k_) == 'table' then
			if  env_filter_ and (env_filter_ ~= k_.e) then
				--过滤
			else
				-- ["123.207.235.22"] = {["t"]=1610007259,["e"]=0,["n"]="keeper_server"}
				if  k_.t then time_ = uu.now() - k_.t end
				if  k_.n == 'keeper_server' then
					stdmap_ip_[ ip_ ] = time_
				else
					if  k_.n == 'room' then
						---过滤房间服
					else
						all_keeper_list_[ ip_ ] = { t=time_, env=k_.e, hostname=k_.n }
					end
				end
			end
		end
	end


	for index_, ip_ in pairs(keys_other_) do
		local str_ = keeper_list_:get(ip_)
		if  log.fast() then
			log.debug_list( index_, ip_ , str_ )
		end

		local time_ = 0
		local k_ = table.loadstring( str_ )
		if  type(k_) == 'table' then
			-- ["123.207.235.22"] = {["t"]=1610007259,["e"]=0,["n"]="map"}
			if  env_filter_ and (env_filter_ ~= k_.e) then
				---过滤
			elseif  not all_keeper_list_[ ip_ ] then
				if  k_.n == 'room' then
					---过滤房间服
				else
					if  k_.t then time_ = uu.now() - k_.t end
					all_keeper_list_[ ip_ ] = { t=time_, env=k_.e, hostname=k_.n }
				end
			else
				log.debug( "ignore doubling ip=" .. ip_ )
			end
		end
	end


	--- 1 对里面所有的IP，再加上系统配置的IP，发送keeper请求
	local need_or_detail_
	if  ngx.ctx.m_params.or_detail == '1' then
		need_or_detail_ = 1
	end

	local wait_threads_ = {}
	for ip_, time_ in pairs( stdmap_ip_ ) do

		if  time_ > 3600 then
			all_keeper_list_[ ip_ ] = { t = time_ }
		else
			local t_ = {
				uin=1166200,
				cmd='keeper_node_command',
				op='check_alive_or',
				or_detail = need_or_detail_,   ---是否同时获得详情
			}

			local thread_ = ngx.thread.spawn( FOO.send_to_keeper, ip_, 8072, t_, _SEND_TIME_OUT_ )    --海外20秒超时
			log.debug_list( "thread spawn send ok", ip_ )
			wait_threads_[ ip_ ] = { thread=thread_, ip=ip_, time=time_ }
		end
	end


	for ip_, thread_data_ in pairs(wait_threads_) do
		local ok_, tmp_keeper_ = ngx.thread.wait( thread_data_.thread )
		log.debug_list( "thread spawn wait ok", thread_data_.ip, uu.to_str( ok_ ) )

		--- {["msg"]="ok",["ret"]=0,["hostname"]="Proxyxianqian\ ",["keeper_ver"]="20201224_01",["env"]=12}
		if  type(tmp_keeper_) == 'table' then
			tmp_keeper_.t = thread_data_.time

			if  not (thread_data_.ip == ip_) then
				log.error( "ERROR: ip not match:" .. thread_data_.ip ..ip_ )
			else
				log.debug( "ip match ok:" .. ip_ )
			end

			all_keeper_list_[ ip_ ] = tmp_keeper_
		end
	end

	all_keeper_list_.ctoken = ngx.ctx.m_params.ctoken
	ns_html_keeper_list.show( all_keeper_list_, (ngx.ctx.m_params.ctrl or "111") )

end



function FOO.getKeeperDetail()
	if  ngx.ctx.m_params.gm_name then
		---ok
	else
		ngx.say( "正在开发中" )
		return
	end

	local ip_ = ngx.ctx.m_params.ip
	if  not ip_ then
		ngx.say( "ip_error" )
		return
	end

	local server_ip_list_
	if  ngx.ctx.m_params.server_ip_list then
		local t_ = uu.split( ngx.ctx.m_params.server_ip_list, ',' )
		if  type(t_) == 'table' and #t_ > 0 then
			server_ip_list_ = t_
		end
	end


	local t_ = {
		uin=1166200,
		cmd='keeper_node_command',
		op='check_alive_or',
		or_detail = 1,
	}

	local modules_limit_ = gg.load_lua_modules_dict_limit()

	local tmp_keeper_ = FOO.send_to_keeper( ip_, 8072, t_, _SEND_TIME_OUT_ )    --海外20秒超时
	if  type(tmp_keeper_) == 'table' then

		--if  ngx.ctx.m_params.log == '1' then
			--uu.var_dump( tmp_keeper_ )
		--end

		tmp_keeper_.modules_limit = modules_limit_ or {}

		tmp_keeper_.ip = ip_
		ns_html_keeper_detail.show( tmp_keeper_,  server_ip_list_ )
	else
		ngx.say( "send_to_keeper_error:" .. ip_ )
	end

end


---center发送命令给keeper
function FOO.sendKeeperMsg()
	local ip_ = ngx.ctx.m_params.ip
	local op_ = ngx.ctx.m_params.op

	if  not ip_ then
		ngx.say( "ip_error" )
		return
	end

	local t_ = {
		uin=1166300,
		cmd='keeper_node_command',
		op=op_,
	}

	local batch_op_ = 1 --是否支持批量操作

	if     op_ == 'reload_nginx_by_config' then
		t_.config_file_list = ngx.ctx.m_params.config_file_list
		t_.confirm = 1
	elseif op_ == 'get_nginx_list' then
		t_.config_file_list = ngx.ctx.m_params.config_file_list
	elseif op_ == 'rsync_code' then
		t_.modules_list     = ngx.ctx.m_params.modules_list
	elseif op_ == 'rsync_code_dry' then
		t_.modules_list     = ngx.ctx.m_params.modules_list
	elseif op_ == 'press_pull_git' then
		batch_op_ = 0           -- 只需要132执行
		ip_ = "120.24.64.132"   -- pull git 只有132上有
	elseif op_ == 'clean_error_log' then
		t_.cmd   = 'post_event'
		t_.event = 'sh'
		t_.event_name = 'clean_error_log'
		t_.shell_ver  = '20211203_01'
	elseif op_ == 'list_error_log' then
		t_.cmd   = 'post_event'
		t_.event = 'sh'
		t_.event_name = 'list_error_log'
		t_.shell_ver  = '20211203_01'
	else
		ngx.say( "op_error" )
		return
	end


	--批量
	if  batch_op_ == 1 and ngx.ctx.m_params.server_ip_list and #ngx.ctx.m_params.server_ip_list >= 7 then

		log.day_list( "center_server", "send_to_keeper", ngx.ctx.m_params.server_ip_list, uu.to_str(t_) )

		local thread_list_ = {}
		local ip_list_ = uu.split( ngx.ctx.m_params.server_ip_list, ',' )
		for i=1, #ip_list_ do
			if  #ip_list_[i] >= 7 then

				local function func_mysql_()
					---一个个发送请求
					local tmp_keeper_ = FOO.send_to_keeper( ip_list_[i], 8072, t_, _SEND_TIME_OUT_ )  --海外20秒超时
					local ret_string_ = '\n batch return from ip ' ..
							'======================================================= '	.. ip_list_[i] .. '\n'
					if  type(tmp_keeper_) == 'table' then
						ret_string_ = ret_string_ .. ( tmp_keeper_.msg or "no_msg" )
					else
						ret_string_ = ret_string_ .. "send_to_keeper_error:" .. ip_
					end
					ngx.say( ret_string_ )
				end
				uu.thread_spawn( func_mysql_, thread_list_ )
			end
		end
		uu.thread_wait( thread_list_ )

	else

		log.day_list( "center_server", "send_to_keeper", ip_, uu.to_str(t_) )

		local tmp_keeper_ = FOO.send_to_keeper( ip_, 8072, t_, _SEND_TIME_OUT_ )  --海外20秒超时
		if  type(tmp_keeper_) == 'table' then
			ngx.say( tmp_keeper_.msg or "no_msg" )
		else
			ngx.say( "send_to_keeper_error:" .. ip_ )
		end
	end

end



---发送一个下次给keeper
function  FOO.send_to_keeper( ip_, port_, t_, exp_time_ )
	--http://120.24.64.132:8087/miniw/keeper?time=1606795051&uin=1166200&cmd=keeper_node_command
	--&token=a0b5341f9dcbb2a9436c20f5eeb8b825&op=check_alive_or
	if  ip_ and port_ and t_ and t_.uin and t_.cmd and t_.op then
		local url_ =  "http://" .. ip_ .. ":" .. port_ .. "/miniw/keeper?"

		t_.time = uu.now()
		t_.token = ns_auth_comm_checker.gen_comm_inner_token( t_.uin, t_.time, t_.cmd );
		url_ = url_ .. ngx.encode_args( t_ )

		log.debug( "send_to_keeper" )
		log.debug( url_ )

		log.day_list( "center_server", "send_to_keeper", url_ )

		local ret_ = ns_network.http_get_lua( url_, nil, nil, (exp_time_ or 3000) )
		if  ret_ then
			uu.var_dump( ret_ )
			return ret_
		else
			log.error( "http_error:" .. url_ )
		end
	else
		log.error( "send_to_keeper, error_params:" .. uu.to_str(t_) )
	end

end



-- 132服务器上报服务器IP和名字对应表
function FOO.reportServerIpName()
	if  ngx.ctx.m_params.gm_name == '132s' then
		---ok
	else
		ngx.say( "正在开发中" )
		return
	end

	-- 读取json信息，存入share_dict中
	ngx.req.read_body();
	--local value_ = ngx.req.get_body_data()
	--log.day_list( "center_server", "reportServerIpName1", value_ )

	local args_ipn_args_ = ngx.req.get_post_args()
	--log.day_list( "center_server", "reportServerIpName2", uu.to_str( args_ipn_ ) )

	local args_ipn_ = {}
	if  args_ipn_args_.content then
		args_ipn_ = uu.json2table( args_ipn_args_.content )
	end

	--存入共享内存中
	for k, v in pairs(args_ipn_) do
		--["159.75.213.253_10.20.60.26"]="____account-dc-01"
		--log.debug( uu.to_str(k) )
		--log.debug( uu.to_str(v) )
		local ips_ = uu.split( k, '_' )

		--log.debug( uu.to_str(ips_) )

		if  type(ips_) == 'table' then
			if  ips_[1] then
				uu.set_server_cache_table( 1, 'ipn_' .. ips_[1], { ip2=ips_[2], v=v }, 86400 )
			end
			if  ips_[2] then
				uu.set_server_cache_table( 1, 'ipn_' .. ips_[2], { ip1=ips_[1], v=v }, 86400 )
			end

			log.day_list( "center_server", "set_cache_ipn", ips_[1], ips_[2], v )
		end
	end

	uu.return_table( {ret=0, msg="ok"} )
end



-- 显示dc工作列表详情
function FOO.showDcList()

	local env_ = ngx.ctx.m_params.env

	local dict_ = ngx.shared.data_cache_list
	local all_report_  = dict_:get_keys(4096)

	local dc_data_ = {}

	for index_, key_ in pairs(all_report_) do
		local str_ = dict_:get(key_)
		local k_ = table.loadstring( str_ )
		if  type(k_) == 'table' and k_.env then

			-- ver_hot=0, load=0, ver_lua=dc_20211025_01f, env=0, ip=124.71.96.103,
			-- post_data=[{"b":6390,"from":"dc","name":"punisher","c":90,"cmd":"read35"},
			-- {"b":536,"from":"dc","name":"punisher","c":50,"cmd":"read34"},select={0:333}],

			if  k_.env == env_ and k_.post_data then
				uu.var_dump( k_ )
				local json_table_ = uu.json2table( k_.post_data )
				if  type(json_table_) == 'table' then

					if  k_.ip then
						for num_, rp_ in pairs(json_table_) do
							if  type(rp_) == 'table' and rp_.name then
								if  not dc_data_[rp_.name]        then dc_data_[rp_.name] = {}                 end
								if  not dc_data_[rp_.name][k_.ip] then dc_data_[rp_.name][k_.ip] = { list={} } end
								table.insert( dc_data_[rp_.name][k_.ip].list, rp_ )

								if  json_table_.select and json_table_.select[rp_.name] and (not dc_data_[rp_.name][k_.ip].select) then
									dc_data_[rp_.name][k_.ip].select = json_table_.select[rp_.name]
									dc_data_[rp_.name][k_.ip].ver_lua = k_.ver_lua
									dc_data_[rp_.name][k_.ip].ver_hot = k_.ver_hot
									dc_data_[rp_.name][k_.ip].rt      = k_.rt
								end
							end
						end
					end

				end
			end
		end
	end

	uu.var_dump( dc_data_ )
	ns_html_dc_list.show( dc_data_, (ngx.ctx.m_params.ctrl or "111") )
end




-- 显示ma_gate工作列表详情
function FOO.showMaGateList()

	local env_ = ngx.ctx.m_params.env

	local dict_ = ngx.shared.ma_gate_list
	local all_report_  = dict_:get_keys(4096)

	local ma_gate_   = {}   --网关
	local target_    = {}   --目标
	local all_call_  = {}   --总计

	for index_, key_ in pairs(all_report_) do
		local str_ = dict_:get(key_)
		local k_ = table.loadstring( str_ )
		if  type(k_) == 'table' and k_.env then
			--uu.var_dump( k_ )
			--{ ver_hot=ma_gate_e0_20210929h, env=0, load=42676, load1=0, rt=1637050804, ip=1.14.165.67, ver_lua=ma_gate_20211112f, --post_data=[
			--{"call":404,  "to":"\/miniw\/battlepass@10.20.60.10:8090","code":"report_batchtask_progress","from":"ma_gate_m_5","cost":1498},
			--{"call":1,    "to":"\/miniw\/battlepass@10.20.60.10:8090","code":"get_task_experience","from":"ma_gate_m_5","cost":4},
			--{"call":1173, "to":"\/miniw\/skin@10.104.130.179:8074","code":"get_custom_motion_seat","from":"ma_gate_m_1","cost":1145},
			--{"call":1,    "to":"\/miniw\/skin@10.104.130.179:8074","code":"buy_custom_motion_seat_position","from":"ma_gate_m_1","cost":44},
			if  k_.env == env_ and k_.post_data then
				uu.var_dump( k_ )
				local json_table_ = uu.json2table( k_.post_data )
				if  type(json_table_) == 'table' then
					if  k_.ip then
						for num_, rp_ in pairs(json_table_) do

							--decode [to]
							local t1_ = string.find( rp_.to, '@' )
							local t2_ = string.find( rp_.to, ':' )
							if  t1_ and t2_ then
								local uri_ = string.sub( rp_.to, 1,     t1_-1 )
								local ip2_ = string.sub( rp_.to, t1_+1, t2_-1 )
								--log.debug_list( uri_, ip2_ )

								local ip1_  = k_.ip
								local code_ = rp_.code

								--gate
								if  not ma_gate_[ip1_]              then ma_gate_[ip1_] = {}        end
								if  not ma_gate_[ip1_][uri_]        then ma_gate_[ip1_][uri_] = {}  end
								if  not ma_gate_[ip1_][uri_][code_] then ma_gate_[ip1_][uri_][code_] = { call=0, cost=0 }  end
								ma_gate_[ip1_][uri_][code_].call = ma_gate_[ip1_][uri_][code_].call + rp_.call
								ma_gate_[ip1_][uri_][code_].cost = ma_gate_[ip1_][uri_][code_].cost + rp_.cost

								--target
								if  not target_[ip2_]              then target_[ip2_] = {}  end
								if  not target_[ip2_][uri_]        then target_[ip2_][uri_] = {}  end
								if  not target_[ip2_][uri_][code_] then target_[ip2_][uri_][code_] = { call=0, cost=0 }  end
								target_[ip2_][uri_][code_].call = target_[ip2_][uri_][code_].call + rp_.call
								target_[ip2_][uri_][code_].cost = target_[ip2_][uri_][code_].cost + rp_.cost

								--all
								if  not all_call_[uri_]        then all_call_[uri_] = {}   end
								if  not all_call_[uri_][code_] then all_call_[uri_][code_] = { call=0, cost=0 } end
								all_call_[uri_][code_].call = all_call_[uri_][code_].call + rp_.call
								all_call_[uri_][code_].cost = all_call_[uri_][code_].cost + rp_.cost
							end
						end
					end
				end
			end
		end

	end

	--uu.var_dump( ma_gate_ )
	--uu.var_dump( target_ )
	--uu.var_dump( all_call_ )

	ns_html_ma_gate_list.show( ma_gate_, target_, all_call_,  { sort=ngx.ctx.m_params.sort , env=env_ } )
end




return FOO;
